package online.keepon.document.service.impl;


import com.github.benmanes.caffeine.cache.Cache;
import online.keepon.document.common.PageInfo;
import online.keepon.document.common.PageInfo.Page;
import online.keepon.document.mapper.ArticleMapper;
import online.keepon.document.mapper.ContentMapper;
import online.keepon.document.model.Article;
import online.keepon.document.model.Content;
import online.keepon.document.model.CountFiltrate;
import online.keepon.document.model.dto.*;
import online.keepon.document.service.ArticleService;
import online.keepon.document.util.DateUtil;
import online.keepon.document.util.Hashids;
import online.keepon.document.util.IpUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author fujie
 * @ 日期 2020-03-19 23:01
 */

@Service
public class ArticleServiceImpl implements ArticleService {

    @Resource
    private ArticleMapper articleMapper;
    @Resource
    private ContentMapper contentMapper;
    @Autowired
    private Cache<String, Object> caffeineCache;
    private static final Hashids hashids = new Hashids("algorithm_salt", 8);

    public String encode(Integer id) {
        return hashids.encode(id);
    }

    public Integer decode(String h) {
        try {
            return Math.toIntExact(hashids.decode(h)[0]);
        } catch (Exception e) {
            return 0;
        }
    }


    @Override
    public int deleteByPrimaryKey(String hid) {
        return articleMapper.deleteByPrimaryKey(decode(hid));
    }

    @Override
    public int recoverByPrimaryKey(String hid) {
        Integer id = decode(hid);
        Article art = articleMapper.selectByPrimaryKey(id);
        if (art != null) {
            if (art.getDel().equals(1)) {
                return deleteByPrimaryKey(hid);
            }
        }
        return articleMapper.recoverByPrimaryKey(id);
    }

    @Override
    @Transactional
    public int insert(ArticleDTO record) {
        Article article = new Article();
        article.setCreateTime(DateUtil.toEpochSecond(LocalDateTime.now()));
        article.setUpdateTime(DateUtil.toEpochSecond(LocalDateTime.now()));
        if (record.getCategoryId() == null) {
            article.setCategoryId(10);
        }
        if (record.getStatus() == null) {
            record.setStatus(2);
        }
        if (record.getType() == null) {
            article.setType("原创");
        }
        article.setTop(0);
        article.setDel(0);
        if (record.getContent().length() < 200) {
            record.setSummary(record.getContent());
        } else {
            record.setSummary(record.getContent().substring(0, 200));
        }
        BeanUtils.copyProperties(record, article);
        int insert = articleMapper.insert(article);
        Content content = new Content();
        content.setArticleId(article.getId());
        content.setContent(record.getContent());
        contentMapper.insert(content);
        return insert;
    }

    @Override
    public Article selectByPrimaryKey(String hid) {
        Integer id = decode(hid);
        String ip = IpUtils.getIp();
        Article article = articleMapper.selectByPrimaryKey(id);
        if (article != null) {
            Object o = caffeineCache.asMap().get(ip + id);
            article.setHid(encode(article.getId()));
            if (o == null) {
                caffeineCache.put(ip + id, id);
                articleMapper.updateReadByID(article.getRead() + 1, id);
            }
        }
        return article;
    }

    @Override
    @Transactional
    public int updateByPrimaryKey(ArticleDTO record) {
        Article article = new Article();
        article.setUpdateTime(DateUtil.toEpochSecond(LocalDateTime.now()));
        if (record.getContent().length() < 200) {
            record.setSummary(record.getContent());
        } else {
            record.setSummary(record.getContent().substring(0, 200));
        }
        BeanUtils.copyProperties(record, article);
        article.setId(decode(record.getHid()));
        Article art = articleMapper.selectByPrimaryKey(article.getId());
        if (art != null) {
            if (art.getDel().equals(1)) {
                article.setDel(0);
            }
        }
        int i = articleMapper.updateByPrimaryKey(article);
        Content content = new Content();
        content.setArticleId(article.getId());
        content.setContent(record.getContent());
        contentMapper.update(content);
        return i;
    }

    private Integer status(String status) {
        switch (status) {
            case "total":
                return null;
            case "open":
                return 0;
            case "secret":
                return 1;
            case "draft":
                return 2;
            case "recycle":
                return 3;
        }
        return 0;
    }

    @Override
    public long countTotal(String status) {
        Integer delete = "recycle".equals(status) ? 1 : 0;
        return articleMapper.countTotal(delete, status(status));
    }


    @Override
    public PageInfo<Article> selectAllByPage(Page page, String status) {
        Integer delete = "recycle".equals(status) ? 1 : 0;
        List<Article> articles = articleMapper.selectAllByPage(page.getOffset(), page.getPageSize(), delete, status(status));
        if (!articles.isEmpty()) {
            for (Article article : articles) {
                article.setHid(encode(article.getId()));
            }
        }
        return new PageInfo<>(articles, page.getPageNum(), page.getPageSize(), page.getTotal());
    }

    @Override
    public List<Article> selectArticlesNews() {
        List<Article> articles = articleMapper.selectArticlesNews();
        if (!articles.isEmpty()) {
            for (Article article : articles) {
                article.setHid(encode(article.getId()));
            }
        }
        return articles;
    }

    @Override
    public List<ArchivesNewsDTO> selectArticleArchivesNews() {

        return articleMapper.selectArticleArchivesNews();
    }


    @Override
    public long selectArticleArchivesCount() {
        return articleMapper.selectArticleArchivesCount();
    }

    @Override
    public PageInfo<ArchivesNewsDTO> selectArticleArchives(Page page) {
        List<ArchivesNewsDTO> articles = articleMapper.selectArticleArchives(page.getOffset(), page.getPageSize());
        if (!articles.isEmpty()) {
            for (ArchivesNewsDTO article : articles) {
                article.setHid(encode(article.getId()));
            }
        }
        return new PageInfo<>(articles, page.getPageNum(), page.getPageSize(), page.getTotal());
    }

    @Override
    public long countCategoriesTotal(String categories) {
        return articleMapper.countCategoriesTotal(categories);
    }

    @Override
    public PageInfo<Article> selectAllCategoriesByPage(Page page, String categories) {
        List<Article> articles = articleMapper.selectAllCategoriesByPage(page.getOffset(), page.getPageSize(), categories);
        if (!articles.isEmpty()) {
            for (Article article : articles) {
                article.setHid(encode(article.getId()));
            }
        }
        return new PageInfo<>(articles, page.getPageNum(), page.getPageSize(), page.getTotal());
    }

    @Override
    public long countTagsTotal(String tags) {
        return articleMapper.countTagsTotal(tags);
    }

    @Override
    public long countSearchTotal(String title) {
        return articleMapper.countSearchTotal(title);
    }

    @Override
    public PageInfo<Article> selectAllSearchByPage(Page page, String title) {
        List<Article> articles = articleMapper.selectAllSearchByPage(page.getOffset(), page.getPageSize(), title);
        if (!articles.isEmpty()) {
            for (Article article : articles) {
                article.setHid(encode(article.getId()));
            }
        }
        return new PageInfo<>(articles, page.getPageNum(), page.getPageSize(), page.getTotal());
    }

    @Override
    public List<Article> selectAll(String open) {
        return articleMapper.selectAllByStatus(open);
    }

    @Override
    public PageInfo<Article> selectAllTagsByPage(Page page, String tags) {
        List<Article> articles = articleMapper.selectAllTagsByPage(page.getOffset(), page.getPageSize(), tags);
        if (!articles.isEmpty()) {
            for (Article article : articles) {
                article.setHid(encode(article.getId()));
            }
        }
        return new PageInfo<>(articles, page.getPageNum(), page.getPageSize(), page.getTotal());
    }

    @Override
    public long selectArticleArchivesConditionCount(String condition) {
        return articleMapper.selectArticleArchivesConditionCount(condition);
    }

    @Override
    public PageInfo<ArchivesNewsDTO> selectArticleArchivesCondition(Page page, String condition) {
        List<ArchivesNewsDTO> articles = articleMapper.selectArticleArchivesConditionCountByPage(page.getOffset(), page.getPageSize(), condition);
        if (!articles.isEmpty()) {
            for (ArchivesNewsDTO article : articles) {
                article.setHid(encode(article.getId()));
            }
        }
        return new PageInfo<>(articles, page.getPageNum(), page.getPageSize(), page.getTotal());
    }

    @Override
    public ArticleItemDTO articleItemCount() {
        return articleMapper.articleItemCount();
    }

    @Override
    public long searchCountTotal(SearchDTO search) {
        return articleMapper.searchCountTotal(search);
    }

    @Override
    public PageInfo<Article> search(SearchDTO search, Page page) {
        List<Article> articles = articleMapper.search(search, page.getOffset(), page.getPageSize());
        if (!articles.isEmpty()) {
            for (Article article : articles) {
                article.setHid(encode(article.getId()));
            }
        }
        return new PageInfo<>(articles, page.getPageNum(), page.getPageSize(), page.getTotal());
    }

    @Override
    public int articleIsTop(String id, Boolean top) {
        return articleMapper.articleIsTop(decode(id), top);
    }

    @Override
    public CountFiltrate totalByFiltrate() {
        return articleMapper.totalByFiltrate();
    }

    @Override
    public List<TagsDTO> selectAllTags() {
        return articleMapper.selectAllTags();
    }
}
